/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package queryexecute;

import org.omg.CORBA.ORB;
import org.omg.CORBA.SystemException;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;

import dgbgui.DGBGUI;
import dgbgui.logging.ErrorLogger;
import dgbgui.modeldocument.QueryResult;
import dgbgui.modeldocument.primitives.AttributeType;
import dgbgui.modeldocument.primitives.ConceptType;
import dgbgui.modeldocument.primitives.DataType;
import dgbgui.modeldocument.primitives.LayerType;
import dgbgui.modeldocument.primitives.Primitive;
import dgbgui.modeldocument.primitives.RelationType;

/**
 * @author bjnortier
 *
 */
public class CorbaExecutor extends QueryExecutor {

    public CorbaExecutor(String queryString) {
        super(queryString);
    }

    public Object construct() {

        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR() );
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iQuery queryParser = iface.get_query_interface();
            QueryResult result = executeViaCorba(queryParser,getQueryString());
            orb.destroy();
            return result;
        } catch (Exception e) {
            // Handle the exception and create a new error result
            // The exception context is during query execution
            handleCorbaException("Query execution: ",e);
            orb.destroy();
            return new QueryResult();
        }
    }
    
    /**
     * @return the DGB data types
     */
    public static DataType[] getDataTypes() {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR() );
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iFunctional functionalInterface = iface.get_functional_interface();
            // Get the dgbCORBA.attribute_t sequence
            dgbCORBA.data_type_t[] corbaTypes = functionalInterface.get_data_types();
            DataType[] nativeTypes = new DataType[corbaTypes.length];
            for ( int k = 0; k < corbaTypes.length; ++k ) { 
                nativeTypes[k] = CorbaToNativeConverter.convert(corbaTypes[k]);
            }
            orb.destroy();
            return nativeTypes;
        } catch (Exception e) {
            orb.destroy();
            handleCorbaException("Initialising data types: ",e);
        }
        return null;
    }
    
    /**
     * @return the DGB attribute types
     */
    public static AttributeType[] getAttributeTypes() {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR() );
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iFunctional functionalInterface = iface.get_functional_interface();

            dgbCORBA.attribute_t[] corbaTypes = functionalInterface.get_attribute_types();
            AttributeType[] nativeTypes = new AttributeType[corbaTypes.length];
            for ( int k = 0; k < corbaTypes.length; ++k ) { 
                nativeTypes[k] = CorbaToNativeConverter.convert(corbaTypes[k]);
            }
            orb.destroy();
            return nativeTypes;
        } catch (Exception e) {
            orb.destroy();
            handleCorbaException("Initialising attribute types: ",e);
        }
        return null;
    }

    /**
     * @return the DGB concept types
     */
    public static ConceptType[] getConceptTypes() {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR());
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iFunctional functionalInterface = iface.get_functional_interface();
            // Get the dgbCORBA.attribute_t sequence, then convert to 
            // native types
            dgbCORBA.concept_t[] corbaTypes = functionalInterface.get_concept_types();
            ConceptType[] nativeTypes = new ConceptType[corbaTypes.length];
            for ( int k = 0; k < corbaTypes.length; ++k ) { 
                nativeTypes[k] = CorbaToNativeConverter.convert(corbaTypes[k]);
            }
            orb.destroy();
            return nativeTypes;
        } catch (Exception e) {
            orb.destroy();
            handleCorbaException("Initialising concept types: ",e);
        }
        return null;
    }
    
    /**
     * @return the DGB relation types
     */
    public static RelationType[] getRelationTypes() {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR());
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iFunctional functionalInterface = iface.get_functional_interface();
            // Get the dgbCORBA.attribute_t sequence, then convert to 
            // native types
            dgbCORBA.relation_t[] corbaTypes = functionalInterface.get_relation_types();
            RelationType[] nativeTypes = new RelationType[corbaTypes.length];
            for ( int k = 0; k < corbaTypes.length; ++k ) { 
                nativeTypes[k] = CorbaToNativeConverter.convert(corbaTypes[k]);
            }
            orb.destroy();
            return nativeTypes;
        } catch (Exception e) {
            orb.destroy();
            handleCorbaException("Initialising relation types: ",e);
        }
        return null;
    }
    
    /**
     * @return the DGB layer types
     */
    public static LayerType[] getLayerTypes() {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR());
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iFunctional functionalInterface = iface.get_functional_interface();
            // Get the dgbCORBA.attribute_t sequence, then convert to 
            // native types
            dgbCORBA.layer_t[] corbaTypes = functionalInterface.get_layer_types();
            LayerType[] nativeTypes = new LayerType[corbaTypes.length];
            for ( int k = 0; k < corbaTypes.length; ++k ) { 
                nativeTypes[k] = CorbaToNativeConverter.convert(corbaTypes[k]);
            }
            orb.destroy();
            return nativeTypes;
        } catch (Exception e) {
            orb.destroy();
            handleCorbaException("Initialising layer types: ",e);
        }
        return null;
    }
    
    
    public static QueryResult getSyncronousResult(String dgbQLString) {
        ORB orb = null;
        try {
            String[] args = new String[1];
            args[0] = new String("");
            orb = ORB.init(args, null);
            org.omg.CORBA.Object obj = orb.string_to_object(getIOR() );
            dgbCORBA.iInterface iface = dgbCORBA.iInterfaceHelper.narrow(obj);
            dgbCORBA.iQuery queryParser = iface.get_query_interface();
            QueryResult result = executeViaCorba(queryParser,dgbQLString);
            orb.destroy();
            return result;
        } catch (Exception e) {
            // Handle the exception and create a new error result
            // The exception context is during query execution
            handleCorbaException("Query execution: ",e);
            orb.destroy();
            return new QueryResult();
        }
    }
    
    /**
     * Handle a CORBA Exception. Parsed here for common CORBA exceptions
     * @param e The Exception
     */
    private static void handleCorbaException(String context, Exception e) {
        boolean logged = false;
        if ( e instanceof SystemException ) {
            
            // Exception occurred when trying to resolve the IOR
            for ( StackTraceElement element : e.getStackTrace() ) {
                if ( element.getMethodName().equals("getIORFromString")) {
                    ErrorLogger.getInstance().logString(context + "IOR could not be resolved. Please check the IOR string.");
                    logged = true;
                }
            }
            
            // Exception occured when trying to create the connection
            for ( StackTraceElement element : e.getStackTrace() ) {
                if ( element.getMethodName().equals("createConnection")) {
                    ErrorLogger.getInstance().logString(context + "Could not create a connection to the DGB server.");
                    logged = true;
                }
            }
            
        }
        
        // The default is to log the exception. As more exceptions are exposed,
        // they should be parsed for better errors messages above
        if ( !logged ) {
            ErrorLogger.getInstance().logException(e);
        }
    }
    
    private static String getIOR() {
        return DGBGUI.getInstance().getDGBProperties().getProperty("IOR").trim();
    }

    private static QueryResult executeViaCorba(dgbCORBA.iQuery queryParser, String queryString) {
        System.out.println("Submitted query... ");
        if ( !queryString.endsWith(";") ) {
            queryString += ";";
        }
        org.omg.CORBA.Any[] corbaResult = queryParser.execute_query(queryString);

        // Create a map of types to lists of those types
        QueryResult results = new QueryResult();
        
        int n = corbaResult.length;
        for (int i = 0; i < n; i++) {
            
            TypeCode type = corbaResult[i].type();
            //System.out.println(type.toString());
            TCKind kind = type.kind();
            //System.out.println(kind.toString());
            switch (kind.value()) {
            case TCKind._tk_struct:
                Primitive primitive = CorbaToNativeConverter.getPrimitive(corbaResult[i]);
                // Add the result
                if ( primitive != null) {
                    System.out.print("R[" + i + "] = " + primitive.summary() + ".");
                    results.addPrimitive(primitive);
                }
                break;
            /*case TCKind._tk_sequence:
                // Don't know how to handle
                assert false;
                break;*/
            default:
                // Not catering for this yet
                //assert false;
                break;
            }
        }
        System.out.println(" Result received");
        return results;
    }


 
}
